#include "udp_client.hpp"
#include <cstring>
#include <pthread.h>

// 127.0.0.1:本地环回，就表示的就是当前主机，通常用来进行本地通信或者测试

// ./udp_client serverip serverport,客户端启动的时候，必须知道服务端的ip和port
// 客户端并不关心自己的ip和port，只需要别人找到自己就行了
static void usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << "serverip serverport\n" << std::endl; // 服务器必须永远有IP地址
}
void *recver(void *args)
{
    int sock = *(static_cast<int *>(args));
    while (true)
    {
        // 收,接受
        char buffer[2048];
        struct sockaddr_in temp; // 客户端也会收到别人的消息，今天就一个服务器，给服务器发消息，一定会收到服务器转回来的消息，默认temp中的字段是server
        // 未来你的客户端也会和别的客户端通信，或者别的服务器通信，可能收消息，来自不同的服务器，所以直接填充&temp
        socklen_t len = sizeof(temp);
        int n = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len);
        if (n > 0)
        {
            buffer[n] = 0;
            // std::cout << "server echo# " << buffer << std::endl;
            std::cout << buffer << std::endl;
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        usage(argv[0]);
        exit(USAGE_ERR);
    }
    std::string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        std::cerr << "create socket error" << std::endl;
        exit(SOCKET_ERR);
    }

    // client 这里要不要bind呢？要的，socket通信的本质[clientip:clientport,server:serverport]
    // client和server在通信时，我们双方地位是对等的，你给我发信息，我也要给你发信息
    // 要不要自己bind呢？自己初始化，自己填一个结构体，然后再来bind，这就是自己bind
    // 不需要自己bind，也不要自己绑定，OS自动给我们进行bind，bind叫系统调用，实际在正常操作时，除了用户直接填一些字段，服务器操作系统本身也是在帮你做工作的
    // 为什么？电脑上，手机上有不同的客户端，这些客户端来自不同的企业，比如，抖音或淘宝等
    // 所以，client的port要随机让OS分配，防止client出现启动冲突
    // 为什么server要自己bind？
    // 1、server的端口不能随意改变，众所周知且不能随意改变
    // 2、服务器都是一家公司的，只要同一家公司，端口号需要统一规范化

    // 明确server是谁
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 服务端不用明确ip，但是客户端要明确server对应的ip地址

    pthread_t tid;
    pthread_create(&tid, nullptr, recver, &sock);

    // 未来客户端不发数据，也有收数据的权利，也要改成多线程，下节课写
    while (true)
    {
        // 先有消息,用户输入，比如平时刷抖音，点的赞等等
        std::string message;
        // std::cout << "[我的服务器]#";
        std::cerr << "Please Enter Your Message# ";
        // std::cin >> message;
        std::getline(std::cin, message);

        // 发
        // 什么时候bind
        // 客户端也要有ip和port，所以一定要绑定，那么什么时候绑定呢？
        // 在我们首次系统调用发送数据的时候，OS会在底层随机选择clientport+自己的IP
        // 1.bind 2.构建发送的数据报文
        //  message.c_str是发送的数据,作为的客户端，发给谁，发给服务端
        sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));

        // // 收,接受
        // char buffer[2048];
        // struct sockaddr_in temp; // 客户端也会收到别人的消息，今天就一个服务器，给服务器发消息，一定会收到服务器转回来的消息，默认temp中的字段是server
        // // 未来你的客户端也会和别的客户端通信，或者别的服务器通信，可能收消息，来自不同的服务器，所以直接填充&temp
        // socklen_t len = sizeof(temp);
        // int n = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len);
        // if (n > 0)
        // {
        //     buffer[n] = 0;
        //     // std::cout << "server echo# " << buffer << std::endl;
        //     std::cout << buffer << std::endl;
        // }
    }

    //close(sock);//在linux上关闭这个文件描述符

    return 0;
}